#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, os
from datetime import datetime

from flask import make_response, abort
from loguru import logger

from config import db
from models.data_model import Person, person_schema, people_schema
from models.data_model import Probe, probe_schema, probes_schema
from models.data_model import Subject, subject_schema, subjects_schema
from models.data_model import Experiment, experiment_schema, experiments_schema
from models.data_model import Acquisition, acquisition_schema, acquisitions_schema

import webapi.pai_global
from webapi.pai_acquisition_controll import AcquisitionControl
from webapi.pai_image_analysis import PAIAnalysis
from webapi.pai_acquisition_data_manage import AcquisitionDataManage

def read_all_person():
    people = Person.query.all()
    return people_schema.dump(people)

def add_one_person(person):
    name = person.get("name")
    existing_person = Person.query.filter(Person.name == name).one_or_none()

    if existing_person is None:
        new_person = person_schema.load(person, session=db.session)
        db.session.add(new_person)
        db.session.commit()
        return person_schema.dump(new_person), 201
    else:
        abort(406, f"Person with name {name} already exists")

def read_all_probe():
    probes = Probe.query.all()
    return probes_schema.dump(probes)

def add_one_probe(probe):
    name = probe.get("name")
    existing_probe = Probe.query.filter(Probe.name == name).one_or_none()

    if existing_probe is None:
        new_probe = probe_schema.load(probe, session=db.session)
        db.session.add(new_probe)
        db.session.commit()
        return probe_schema.dump(new_probe), 201
    else:
        abort(406, f"Probe with name {name} already exists")


def add_one_subject(subject):
    name = subject.get("name")
    existing_subject = Subject.query.filter(Subject.name == name).one_or_none()

    if existing_subject is None:
        new_subject = subject_schema.load(subject, session=db.session)
        db.session.add(new_subject)
        db.session.commit()
        return subject_schema.dump(new_subject), 201
    else:
        abort(406, f"Subject with name {name} already exists")

def read_all_subject():
    subjects = Subject.query.all()
    return subjects_schema.dump(subjects)

## create an experiment
def add_one_experiment(experiment):
    person_name = experiment.get("person_name")
    subject_name = experiment.get("subject_name")
    probe_name = experiment.get("probe_name")
    logger.debug("start add_one_experiment. request info for new experiment: {0}, {1}, {2}", person_name, subject_name, probe_name)
    new_experiment = experiment_schema.load(experiment, session=db.session)

    date_time_now = datetime.now()
    acq_controll = webapi.pai_global.get_value("AcquisitionControl")
    experimentDataFolder = acq_controll.generateExperimentFolder(person_name, subject_name, probe_name, date_time_now)

    current_probe = Probe.query.filter(Probe.name == probe_name).one_or_none()
    acq_controll.setCurrentProbe(current_probe)

    new_experiment.exp_data_path = experimentDataFolder
    new_experiment.timestamp = date_time_now
    db.session.add(new_experiment)
    db.session.commit()
    logger.debug("end add_one_experiment.")
    return experiment_schema.dump(new_experiment), 201

## create an acquisition
## method: 为acquisiton method name
## mode: 为acquisition mode，single_acquisition, continuous_acquisition
def add_one_acquisition(acquisition, method, mode):
    logger.debug("start add_one_acquisition. acquisition method: {0}, acquisition mode:{1}", method, mode)

    experiment_id = acquisition.get("experiment_id")
    sampling_frequency = acquisition.get("sampling_frequency")
    laser_wavelength = acquisition.get("laser_wavelength")
    laser_energy = acquisition.get("laser_energy")
    trigger_mode = acquisition.get("trigger_mode")
    sampling_num = acquisition.get("sampling_num")
    tx2rx_delay = acquisition.get("tx2rx_delay")
    trigger_num = acquisition.get("trigger_num")
    trigger_period = acquisition.get("trigger_period")
    trigger_delay = acquisition.get("trigger_delay")
    line_number = acquisition.get("line_number")
    pulse_width = acquisition.get("pulse_width")
    pulse_pattern = acquisition.get("pulse_pattern")
    pulse_repeat_num = acquisition.get("pulse_repeat_num")
    acq_pa_LNA = acquisition.get("acq_pa_LNA")
    acq_pa_PGA = acquisition.get("acq_pa_PGA")
    acq_pa_Attenuation = acquisition.get("acq_pa_Attenuation")
    acq_us_LNA = acquisition.get("acq_us_LNA")
    acq_us_PGA = acquisition.get("acq_us_PGA")
    acq_us_Attenuation = acquisition.get("acq_us_Attenuation")
    acq_voltage = acquisition.get("acq_voltage")

    existing_exp = Experiment.query.filter(Experiment.id == experiment_id).one_or_none()
    if existing_exp is None:
        abort("Experiment with id {experiment_id} does not exist. Acquisition cannot be created. ", 400)
    
    person_name = existing_exp.person_name
    subject_name = existing_exp.subject_name
    probe_name = existing_exp.probe_name
    exp_data_folder = existing_exp.exp_data_path

    date_time_now = datetime.now()
    acq_controll = webapi.pai_global.get_value("AcquisitionControl")

    acq_data_folder = acq_controll.startAcquisition(mode, trigger_mode,
                                 sampling_num,
                                 tx2rx_delay,
                                 trigger_num,
                                 trigger_period,
                                 trigger_delay,
                                 line_number,
                                 pulse_width,
                                 pulse_pattern,
                                 pulse_repeat_num,
                                 acq_us_LNA,
                                 acq_us_PGA,
                                 acq_us_Attenuation,
                                 acq_pa_LNA,
                                 acq_pa_PGA,
                                 acq_pa_Attenuation,
                                 laser_wavelength,
                                 exp_data_folder,
                                 person_name,
                                 subject_name,
                                 probe_name,
                                 date_time_now,
                                 acq_voltage, 
                                 method)
    
    new_acquisition = acquisition_schema.load(acquisition, session=db.session)

    new_acquisition.acquisition_method = method
    new_acquisition.acq_data_path = acq_data_folder
    new_acquisition.timestamp = date_time_now
    db.session.add(new_acquisition)
    db.session.commit()
    return acquisition_schema.dump(new_acquisition), 201

## 获取一次acquisition下所有的文件
def get_acquisition_file(acquisition_id):
    logger.debug("start get_acquisition_file. input parameters: acquisition_id-{0}, ", acquisition_id)

    pai_analysis = webapi.pai_global.get_value("PAIAnalysis")
    pai_analysis.setCurrentAcquisitionID(acquisition_id)

    acq_data_folder = pai_analysis.getCurrentAcquisitionPath()
    if acq_data_folder is None or not acq_data_folder.strip() :
        abort("Acquisition with id {0} does not exist or the property acq_data_path of Acquisition is not set. ".format(acquisition_id), 400)
    
    acq_files = {"acquisition_id":acquisition_id, "acquisition_files":[]}

    for file_name in os.listdir(acq_data_folder):
        if os.path.isfile(os.path.join(acq_data_folder, file_name)):
            if file_name.endswith('.bin'):
                acq_files["acquisition_files"].append(file_name)

    logger.debug("end get_acquisition_file. get bin files of acquisition with id : {0}.", acquisition_id)

    return acq_files, 200

## 根据experiment id获取此实验下所有的acquisition info (acquisition id，采集激光波长)
def get_acquisition_info(experiment_id):
    logger.debug("start get_acquisition_info. input parameters: experiment_id-{0}.", experiment_id)
    acq_data_manage = webapi.pai_global.get_value("AcquisitionDataManage")
    acq_list = acq_data_manage.getAcquisitionInfo(experiment_id)
    if not acq_list:
        return "There is no acquisition for the given experiment_id", 500

    logger.debug("end get_acquisition_info.")
    return acquisitions_schema.dump(acq_list), 200

## 根据acquisition id获取其对应的experiment info
def get_experiment_info(acquisition_id):
    logger.debug("start get_experiment_info input parameters: acquisition_id-{0}.", acquisition_id)
    acq_data_manage = webapi.pai_global.get_value("AcquisitionDataManage")
    experiment = acq_data_manage.getExperimentInfo(acquisition_id)
    if not experiment:
        return "Find no experimnets for the given acquisition_id. ", 500
    logger.debug("end get_experiment_info.")

    return experiment_schema.dump(experiment), 200

## 根据条件获取acquisition记录
# person_name， experimentdate，subject_name都为空时返回所有acquisition数据，如有一个不为空则查询
# 查询后根据countperpage进行分页，如果pageindex为空，默认返回第1页的数据
# 返回的数据 acquisition_id，person_name, experimentdate, subject_name, probe_name, 
# acquisition method， 激光波长， 激光能量， remark
def get_acquisition_records(acquisition_query):
    logger.debug("get_acquisition_records input parameters: query parameters-{0}.", acquisition_query)

    acq_data_manage = webapi.pai_global.get_value("AcquisitionDataManage")

    person_name = acquisition_query.get("person_name")
    experimentdate = acquisition_query.get("experimentdate")
    subject_name = acquisition_query.get("subject_name")
    pageindex = acquisition_query.get("pageindex")
    countperpage = acquisition_query.get("countperpage")

    filtered_records = []
    response_result = {"records":filtered_records, "records_count": len(filtered_records)}
    if person_name.strip() == "" and experimentdate.strip() == "" and subject_name.strip() == "":
        filtered_records = acq_data_manage.updateAllAcquisitionRecords()
    else:
        acq_data_manage.updateAllAcquisitionRecords()
        filtered_records = acq_data_manage.fuzzyQuery(person_name, experimentdate, subject_name)

    if pageindex in (0, 1) or pageindex is None:
        if len(filtered_records) <= countperpage:
            response_result["records"] = filtered_records
            response_result["records_count"] = len(filtered_records)
            return response_result, 200
        else:
            response_result["records"] = filtered_records[0:countperpage]
            response_result["records_count"] = len(filtered_records)
            return response_result, 200
    else:
        response_result["records"] = filtered_records[(pageindex - 1) * countperpage : pageindex * countperpage]
        response_result["records_count"] = len(filtered_records)
        return response_result, 200

## 删除采集记录
## 删除数据库中的acquisition记录，删除acquisition的文件，
## 如果一个experiment下的acquisition都删除了，也删除experiment记录，删除experiment对应的文件夹
def delete_acquisition_records(acquisition_id_list):
    logger.debug("start delete_acquisition_records. input parameters: acquisition_id-{0}, ", acquisition_id_list)

    acq_data_manage = webapi.pai_global.get_value("AcquisitionDataManage")
    for acq_id in acquisition_id_list:
        acq_data_manage.deleteAcquisitionRecords(acq_id)

    logger.debug("end delete_acquisition_records. ")
    return "Successfully delete the records of the acquisition.", 204


def export_acquisition_records(acquisition_id_list, folder_path):
    logger.debug("start export_acquisition_records input parameters: acquisition_id-{0}, export folder path:{1}. ", acquisition_id_list, folder_path)

    acq_data_manage = webapi.pai_global.get_value("AcquisitionDataManage")
    for acq_id in acquisition_id_list:
        acq_data_manage.exportAcquisitionRecords(acq_id, folder_path)

    logger.debug("end export_acquisition_records input parameters: acquisition_id-{0}, export folder path:{1}. ", acquisition_id_list, folder_path)
    return "Successfully export the records of the acquisition.", 200


if __name__ == "__main__":
    pass